/******************************************************************************
 * * hal_wlan_pc.c - simulate wlan stack in sdk
 *
 * *(C) Copyright 2020 Asr International Ltd.
 * * All Rights Reserved
 * ******************************************************************************/

/*********************
 *      INCLUDES
 *********************/
#include <stdio.h>
#include "hal_wlan.h"

#if USE_LV_WLAN != 0
#ifdef BUILD_IN_PC_SIMULATOR

#include "wlan_inc/wlan_sta_api.h"
#include "wlan_inc/lwip_api.h"

/*********************
 *      DEFINES
 *********************/
#define HAL_DUMMY_MAX_AP_NUM    10

#define HAL_WLAN_PC_RSSI_MIN    -100
#define HAL_WLAN_PC_RSSI_MAX    -55

/**********************
 *      TYPEDEFS
 **********************/
typedef struct {
    char ssid[32+1];     /* ssid max len:32. +1 is for '\0' when ssidlen is 32  */
    char pwd[64+1];      /* pwd max len:64. +1 is for '\0' when pwdlen is 64 */
    char bssid[6];       /* BSSID of the wlan needs to be connected.*/
    char channel;        /* wifi channel 0-13.*/
    char security;       /* refer to wlan_security_type_e*/
    int8_t power;
} hal_wlan_pc_dummy_ap_info_t;

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void hal_wlan_dummy_ap_power_chg_task_cb(lv_task_t * task);
static void hal_wlan_dummy_open_task_cb(lv_task_t * task);
static void hal_wlan_dummy_scan_task_cb(lv_task_t * task);
static void wlan_active_task_cb(lv_task_t * task);

/**********************
 *  STATIC VARIABLES
 **********************/
static hal_wlan_pc_dummy_ap_info_t dummy_ap_list[HAL_DUMMY_MAX_AP_NUM] = {};
static wlan_sta_cb_stat_chg dummy_stat_chg_cb = NULL;
static wlan_cb_scan_compeleted dummy_scan_compeleted_cb = NULL;
static wlan_sta_err_stat_handler dummy_err_stat_cb = NULL;
static wlan_sta_cb_rssi dummy_rssi_cb = NULL;
static lv_task_t * dummy_task_ap_chg = NULL;
static lv_task_t * dummy_task_scan = NULL;
static lv_task_t * dummy_task_open = NULL;
static lv_task_t * dummy_task_rssi = NULL;
static wlan_sta_err_status_e err_code;
static uint8_t act_ap_id;
static bool is_wlan_active = false;
static bool is_lte = true;
static bool is_ip_got = false;
static bool is_reset = false;

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 ***********************/
int GetWiFiType(void)
{
    return HERON_CHIP;
}

int sdio_init(int sd_slot, int wifi_pwr_en, int wifi_int_host, int wifi_pwr_reset,
              int host_wakeup_wifi, int sys_clk_32k)
{
    return 0;
}

int sdio_wifi_open(void)
{
    return 0;
}

void sdio_wifi_close(void)
{
}

int wlan_wifi_open(wlan_wifi_init_type_t * init_info)
{
    if(is_reset) {
        printf("%s: reset\n", __FUNCTION__);
        return 0;
    }

    printf("%s\n", __FUNCTION__);

    //return -1;

    /* init dummy wifi ap for pc simulator */
    uint8_t i = 0;
    for(;i < (HAL_DUMMY_MAX_AP_NUM - 4);i++) {
        snprintf(dummy_ap_list[i].ssid, 32 + 1, "Dummy Wifi %d", i);
        dummy_ap_list[i].power = -45 - i * 5;
        dummy_ap_list[i].bssid[0] = i;
        dummy_ap_list[i].channel = (i % 13) + 1; /* 1-13 */
        if(0 == i) {
            dummy_ap_list[i].security = WLAN_SECURITY_WEP;
            snprintf(dummy_ap_list[i].pwd, 64 + 1, "%d0000", i);
        } else {
            dummy_ap_list[i].security = WLAN_SECURITY_AUTO;
            snprintf(dummy_ap_list[i].pwd, 64 + 1, "%d0000000", i);
        }
    }

    snprintf(dummy_ap_list[i].ssid, 32 + 1, "Dummy Wifi %d", i - 1);
    dummy_ap_list[i].power = -45 - i * 5;
    dummy_ap_list[i].bssid[0] = i;
    dummy_ap_list[i].channel = (i % 13) + 1; /* 1-13 */
    dummy_ap_list[i].security = WLAN_SECURITY_AUTO;
    snprintf(dummy_ap_list[i].pwd, 64 + 1, "%d0000000", i);
    i++;

    snprintf(dummy_ap_list[i].ssid, 32 + 1, "Dummy Wifi %d", i);
    dummy_ap_list[i].power = -45 - i * 5;
    dummy_ap_list[i].bssid[0] = i;
    dummy_ap_list[i].channel = (i % 13) + 1; /* 1-13 */
    dummy_ap_list[i].security = WLAN_SECURITY_MAX;
    snprintf(dummy_ap_list[i].pwd, 64 + 1, "%d0000000", i);
    i++;

    snprintf(dummy_ap_list[i].ssid, 32 + 1, "abcdefghijklmnopqrstuvwxyz");
    dummy_ap_list[i].power = -45 - i * 5;
    dummy_ap_list[i].bssid[0] = i;
    dummy_ap_list[i].channel = (i % 13) + 1; /* 1-13 */
    dummy_ap_list[i].security = WLAN_SECURITY_OPEN;
    Hal_Mem_Set(dummy_ap_list[i].pwd, 0, 64 + 1);
    i++;

    // hidden ap
    Hal_Mem_Set(dummy_ap_list[i].ssid, 0, 32 + 1);
    dummy_ap_list[i].power = -45 - i * 5;
    dummy_ap_list[i].bssid[0] = i;
    dummy_ap_list[i].channel = (i % 13) + 1; /* 1-13 */
    dummy_ap_list[i].security = WLAN_SECURITY_AUTO;
    Hal_Mem_Copy(dummy_ap_list[i].pwd, "12345678", 9);

    if(NULL == dummy_task_ap_chg) {
        dummy_task_ap_chg = lv_task_create(hal_wlan_dummy_ap_power_chg_task_cb,
                                           2000, LV_TASK_PRIO_MID, NULL);
    }

    return 0;
}

int wlan_wifi_close(void)
{
    printf("%s\n", __FUNCTION__);

    if(dummy_task_open) {
        if(dummy_task_open->user_data) {
            Hal_Mem_Free(dummy_task_open->user_data);
            dummy_task_open->user_data = NULL;
        }
        lv_task_del(dummy_task_open);
        dummy_task_open = NULL;
    }
    if(dummy_task_scan) {
        lv_task_del(dummy_task_scan);
        dummy_task_scan = NULL;
    }
    if(dummy_task_rssi) {
        lv_task_del(dummy_task_rssi);
        dummy_task_rssi = NULL;
    }

    return 0;
}

int wlan_sta_connect(wlan_wifi_init_type_t * init_info)
{
    printf("%s:\n", __FUNCTION__);

    if(NULL == init_info) return -1;

    if((0 == strlen(init_info->ssid)) && (0 == strlen(init_info->key))) {
        // only enter station mode
        return 0;
    }

    if(NULL == dummy_stat_chg_cb) return -2;

    if(dummy_task_rssi) {
        lv_task_del(dummy_task_rssi);
        dummy_task_rssi = NULL;
    }

    wlan_wifi_init_type_t * msg = Hal_Mem_Alloc(sizeof(wlan_wifi_init_type_t));
    Hal_Mem_Copy(msg, init_info, sizeof(wlan_wifi_init_type_t));
    if(dummy_task_open) {
        printf("%s: warning, dummy_task_open is not NULL\n", __FUNCTION__);
        lv_task_del(dummy_task_open);
    }
    dummy_task_open = lv_task_create(hal_wlan_dummy_open_task_cb, 2000,
                                     LV_TASK_PRIO_HIGH, msg);
    lv_task_once(dummy_task_open);

    return 0;
}

int wlan_sta_disconnect(uint8_t * mac)
{
    printf("%s:\n", __FUNCTION__);
    err_code = WLAN_STA_MODE_USER_CLOSE;
    if(dummy_err_stat_cb) {
        dummy_err_stat_cb(err_code);
    }
    if(dummy_stat_chg_cb) {
        dummy_stat_chg_cb(EVENT_STATION_DOWN);
    }
    if(dummy_task_rssi) {
        lv_task_del(dummy_task_rssi);
        dummy_task_rssi = NULL;
    }
    if(dummy_task_open) {
        lv_task_del(dummy_task_open);
        dummy_task_open = NULL;
    }
    is_wlan_active = false;

    return 0;
}

int wlan_sta_start_scan(void)
{
    printf("%s\n", __FUNCTION__);

    if(NULL == dummy_scan_compeleted_cb) return -1;

    if(dummy_task_scan) {
        printf("%s: warning, scanning\n", __FUNCTION__);
    }
    dummy_task_scan = lv_task_create(hal_wlan_dummy_scan_task_cb, 2000, LV_TASK_PRIO_HIGH, NULL);
    lv_task_once(dummy_task_scan);

    return 0;
}

int wlan_stat_chg_cb_register(wlan_sta_cb_stat_chg fn)
{
    dummy_stat_chg_cb = fn;
    return 0;
}

int wlan_scan_compeleted_cb_register(wlan_cb_scan_compeleted fn)
{
    dummy_scan_compeleted_cb = fn;
    return 0;
}

int wlan_sta_err_stat_cb_register(wlan_sta_err_stat_handler fn)
{
    dummy_err_stat_cb = fn;
    return 0;
}

int wlan_sta_rssi_cb_register(wlan_sta_cb_rssi fn)
{
    dummy_rssi_cb = fn;
    return 0;
}

int wlan_get_err_code(unsigned char mode)
{
    return err_code;
}

void wlan_set_max_reconnect_scan(unsigned char counter)
{
}

int wlan_sta_signal_level_get(wlan_sta_signal_level_t * rssi)
{
    rssi->rssi_signal = dummy_ap_list[act_ap_id].power;
    return 0;
}

void wlan_set_close_cause(unsigned char turn_off_wlan)
{
    printf("%s: turn_off_wlan %d\n", __FUNCTION__, turn_off_wlan);
}

uint8_t GetWifiConfigFlag(void)
{
    return 1;
}

void get_ntp_time(void)
{
}

uint8_t uos_timer_create(void **pptimer)
{
    return 0;
}

uint8_t uos_timer_start(void *ptimer, uint32_t ticks, uint32_t repeaticks,
                        void (*callback)(uint32_t), uint32_t param)
{
    return 0;
}

uint8_t uos_timer_delete(void *ptimer)
{
    return 0;
}

TASK_HANDLE *uos_create_task(PTASK_ENTRY pTaskEntry, void *pParameter, uint16_t nMsgQSize,
                             uint32_t nStackSize, uint8_t nPriority, const char *pTaskName)
{
    TASK_ID * id = Hal_Mem_Alloc(sizeof(TASK_ID));
    return (TASK_HANDLE *)id;
}

const char * lwip_get_netif_uap_ifname(void)
{
    static char name[] = "wlan";
    return name;
}

int lwip_ifconfig_value(char * netif_name, char * config_name, int config_value)
{
    if((0 == strcmp(config_name, "ifact4"))
       && (LWIP_NETIF_IF_STATUS_ACTIVE == config_value)) {
        lv_task_t * task = lv_task_create(wlan_active_task_cb, 3000, LV_TASK_PRIO_HIGH, NULL);
        lv_task_once(task);
    }
    return 0;
}

int lwip_iflist(char * netif_name, char * list_name, char * list_value)
{
    if(false == is_wlan_active) return -1;

    if(0 != strcmp(list_name, "ip")) return -1;

    if(NULL == list_value) return -1;

    char ip[] = "192.168.1.100";
    Hal_Mem_Copy(list_value, ip, strlen(ip) + 1);

    is_ip_got = true;

    return 0;
}

int32_t CM_SetConnectionSwitch(bool on_off)
{
    printf("%s: new %d, old %d\n", __FUNCTION__, on_off, is_lte);
    is_lte = on_off;
    return 0;
}

bool CM_GetConnectionSwitch(void)
{
    printf("%s: %d\n", __FUNCTION__, is_lte);
    return is_lte;
}

void wifi_lcdWakeup(bool onoff)
{
    printf("%s: onoff %d\n", __FUNCTION__, onoff);
}

void wifi_inform_dhcp_complete(void)
{
    printf("%s\n", __FUNCTION__);
}

/**********************
 *   STATIC FUNCTIONS
 ***********************/
static void hal_wlan_dummy_scan_task_cb(lv_task_t * task)
{
    printf("%s:\n", __FUNCTION__);

    dummy_task_scan = NULL;

    wlan_scan_result_t *result = (wlan_scan_result_t *)Hal_Mem_Alloc(sizeof(wlan_scan_result_t));
    Hal_Mem_Set(result, 0, sizeof(wlan_scan_result_t));
    for(uint8_t i = 0;i < HAL_DUMMY_MAX_AP_NUM;i++) {
        if(0 > dummy_ap_list[i].power) {
            result->ap_num++;
        }
    }
    if(0 < result->ap_num) {
        result->ap_list = Hal_Mem_Alloc(44 * result->ap_num);
        Hal_Mem_Set(result->ap_list, 0, 44 * result->ap_num);
        uint8_t j = 0;
        for(uint8_t i = 0;i < HAL_DUMMY_MAX_AP_NUM;i++) {
            if(0 > dummy_ap_list[i].power) {
                strcpy(result->ap_list[j].ssid, dummy_ap_list[i].ssid);
                result->ap_list[j].rssi = dummy_ap_list[i].power;
                Hal_Mem_Copy(result->ap_list[j].bssid, dummy_ap_list[i].bssid, 6);
                result->ap_list[j].channel = dummy_ap_list[i].channel;
                result->ap_list[j].security = dummy_ap_list[i].security;
                printf("%s:%s,sec %d,ch %d,rssi %d\n", __FUNCTION__,
                       result->ap_list[j].ssid, result->ap_list[j].security,
                       result->ap_list[j].channel, result->ap_list[j].rssi);
                j++;
            }
        }
    }
    dummy_scan_compeleted_cb(result);
}

static void hal_wlan_dummy_act_ap_rssi_task_cb(lv_task_t * task)
{
    static char step = 3;
    dummy_ap_list[act_ap_id].power += step;
    if((HAL_WLAN_PC_RSSI_MAX + 10) <= dummy_ap_list[act_ap_id].power) {
        step = -3;
    } else if((HAL_WLAN_PC_RSSI_MIN + 10) >= dummy_ap_list[act_ap_id].power) {
        step = 3;
    }
    if(dummy_rssi_cb) {
        dummy_rssi_cb(hal_wlan_rssi_level_calc(dummy_ap_list[act_ap_id].power),
                      dummy_ap_list[act_ap_id].power);
    }

#if 0
    static uint8_t count = 0;
    if(is_ip_got) {
        count++;
    }
    printf("%s: count %d\n", __FUNCTION__, count);
    if(3 == count) {
        if(dummy_stat_chg_cb) {
            dummy_ap_list[act_ap_id].power = 0;
            is_ip_got = false;
            dummy_stat_chg_cb(EVENT_STATION_DOWN);
        }
        lv_task_del(dummy_task_rssi);
        dummy_task_rssi = NULL;
    }
#endif
}

static void hal_wlan_dummy_open_task_cb(lv_task_t * task)
{
    printf("%s:\n", __FUNCTION__);

    dummy_task_open = NULL;

    err_code = WLAN_STA_MODE_NO_AP_FOUND;
    wlan_wifi_init_type_t * init_info = (wlan_wifi_init_type_t *)task->user_data;
    printf("%s: %s,%d:%d:%d:%d:%d:%d,ch %d,sec %d,pwd %s\n", __FUNCTION__, init_info->ssid,
           init_info->mac_addr[0], init_info->mac_addr[0], init_info->mac_addr[0],
           init_info->mac_addr[0], init_info->mac_addr[0], init_info->mac_addr[0],
           init_info->channel, init_info->security, init_info->key);
    bool open_ok = false;
    for(uint8_t i = 0;i < HAL_DUMMY_MAX_AP_NUM;i++) {
        if((0 == strlen(dummy_ap_list[i].ssid))
           || (0 == strcmp(dummy_ap_list[i].ssid, init_info->ssid))) {
            if(0 == dummy_ap_list[i].power) {
                break;
            }
            if(dummy_ap_list[i].security == init_info->security) {
                if(HAL_WLAN_SIGNAL_STRENGTH_NO == hal_wlan_rssi_level_calc(dummy_ap_list[i].power)) {
                    break;
                }
                if(HAL_WLAN_SECURITY_OPEN == init_info->security) {
                    open_ok = true;
                    act_ap_id = i;
                    break;
                }
                if(0 == strcmp(dummy_ap_list[i].pwd, init_info->key)) {
                    open_ok = true;
                    act_ap_id = i;
                    break;
                } else {
                    err_code = WLAN_STA_MODE_PASSWORD_ERR;
                }
                break;
            }
        }
    }
    Hal_Mem_Free(task->user_data);
    task->user_data = NULL;

    printf("%s: open_ok %d, err_code %d\n", __FUNCTION__, open_ok, err_code);
    if(open_ok) {
        if(dummy_stat_chg_cb) {
            dummy_stat_chg_cb(EVENT_STATION_UP);
        }
        dummy_task_rssi = lv_task_create(hal_wlan_dummy_act_ap_rssi_task_cb,
                                         2000, LV_TASK_PRIO_MID, NULL);
    } else {
        is_reset = true;
        err_code = WLAN_STA_MODE_PASSWORD_ERR;
        if(dummy_err_stat_cb) {
            dummy_err_stat_cb(err_code);
        }
        if(dummy_stat_chg_cb) {
            dummy_stat_chg_cb(EVENT_STATION_DOWN);
        }
    }
}

static void hal_wlan_dummy_ap_power_chg_task_cb(lv_task_t * task)
{
    for(uint8_t i = 0;i < HAL_DUMMY_MAX_AP_NUM;i++) {
        //Dummy_Ap_List[i].Power = (Dummy_Ap_List[i].Power + i + 10) % 100;
    }
}

static void wlan_active_task_cb(lv_task_t * task)
{
    is_wlan_active = true;
}

#endif
#endif/*USE_LV_WLAN*/
